Skip to content

HTTPS 与 TLS 握手

作者:青见春山
发表于:2026-07-29
字数统计:7500 字
预计阅读26分钟

涵盖 HTTPS 概念、对称加密 vs 非对称加密、TLS 1.2 与 1.3 握手流程、CA 证书、SSL 与 TLS 的关系、混合加密的工程实践。

一、HTTP vs HTTPS

1. 基本概念

Plain
HTTP(HyperText Transfer Protocol):
- 明文传输,端口 80
- 数据不加密,可以被窃听、篡改

HTTPS(HTTP Secure):
- HTTP + TLS(传输层安全)
- 端口 443
- 加密传输,防止窃听;校验完整性,防止篡改;身份认证,防止冒充

2. HTTPS 的三大作用

Plain
1. 数据保密性:通过加密防止被窃听
2. 数据完整性:MAC 校验防止被篡改
3. 身份认证:CA 证书验证服务器身份,防止被冒充

3. HTTPS 协议栈

Plain
┌─────────────────────┐
│   HTTP 协议          │  ← 应用层
├─────────────────────┤
│   TLS 协议           │  ← HTTP/1.1、HTTP/2 通常在 TCP 之上
├─────────────────────┤
│   TCP 协议           │  ← 传输层
├─────────────────────┤
│   IP 协议            │  ← 网络层
└─────────────────────┘

HTTP/3 是例外:它运行在基于 UDP 的 QUIC 上,TLS 1.3 握手能力集成在 QUIC 中。

二、加密基础

1. 对称加密

Plain
特点:加密和解密使用同一个密钥
常见算法:DES、3DES、AES、ChaCha20

优点:
- 速度快(适合大数据量加密)
- 适合数据加密

缺点:
- 密钥传输不安全(怎么把密钥给对方?)
- 多人通信需要维护多个密钥对

示意:
明文 --[密钥 K]--> 密文
密文 --[密钥 K]--> 明文

2. 非对称加密

Plain
特点:加密和解密使用不同密钥(公钥 + 私钥)
常见体系:RSA;基于椭圆曲线的加密/签名方案;DH/ECDH 密钥协商。DH/ECDH 是密钥协商机制,不是“用公钥加密、私钥解密”的加密算法。

公钥:公开,任何人都可以拿到
私钥:保密,只有拥有者知道

用法 1(加密通信):
公钥加密 → 私钥解密(任何人都能发消息,只有私钥持有者能读)
明文 --[公钥]--> 密文
密文 --[私钥]--> 明文

用法 2(数字签名):
私钥签名 → 公钥验证(证明消息确实是私钥持有者发的)
签名 --[公钥]--> 验证通过/失败

优点:
- 公钥可以公开传输,私钥保密
- 解决密钥分发问题

缺点:
- 计算成本通常显著高于对称加密,具体差距取决于算法、参数、硬件与操作类型
- 不适合加密大量数据

3. 混合加密(工程实践)

Plain
实际 TLS 用法(混合密码系统):
1. 握手中通过认证和密钥协商建立共享秘密;现代 TLS 通常使用(EC)DHE 协商,而不是直接传输会话密钥
2. 用对称加密传输数据(解决速度问题)

完整流程:
- 客户端与服务端交换临时密钥协商参数,并验证服务端证书与签名
- 双方各自计算相同的共享秘密,再派生流量密钥
- 后续通信使用派生出的对称密钥进行认证加密

4. 摘要算法 / 哈希算法

Plain
特点:单向函数,不可逆(理论上)
常见算法:MD5(已被攻破)、SHA-1(已被攻破)、SHA-256、SHA-3

用途:
- 验证数据完整性(发送方算 hash,接收方重算,对比)
- 密码存储(使用带随机盐、成本可调的专用密码哈希/KDF,如 Argon2、scrypt、bcrypt 或 PBKDF2;不能直接存普通 SHA-256)
- 数字签名(先 hash 再签名)

注意:hash 不是加密!加密是可逆的,hash 是不可逆的

5. 数字签名

Plain
过程:
1. 发送方:对消息算 hash(hash M = H(M))
2. 发送方:使用私钥和签名算法对摘要或消息生成签名
3. 发送方:发送消息 M + 签名 S
4. 接收方:使用发送方公钥和对应签名算法验证签名
5. 签名算法结合收到的消息摘要判断验证是否通过
6. 相同 → 消息完整且确实是发送方发的

三、TLS 握手流程

1. TLS 1.2 完整握手(以旧式 RSA 密钥交换为例)

Plain
客户端                                              服务端
  │                                                    │
  │──────── ① ClientHello ────────────────────────────→│
  │   - 支持的 TLS 版本                                │
  │   - 客户端随机数 (client random)                   │
  │   - 客户端支持的密码套件                            │
  │   - Session ID(如果有)                           │
  │                                                    │
  │←──────── ② ServerHello ───────────────────────────│
  │   - 选定的 TLS 版本                                │
  │   - 服务端随机数 (server random)                   │
  │   - 选定的密码套件                                 │
  │   - Session ID                                     │
  │                                                    │
  │←──────── ③ Certificate ───────────────────────────│
  │   - 服务器证书链                                   │
  │   - 包含公钥                                       │
  │                                                    │
  │←──────── ④ ServerHelloDone ───────────────────────│
  │                                                    │
  │                                                    │
  │  客户端验证证书                                     │
  │  用服务器公钥加密 pre-master secret                │
  │                                                    │
  │──────── ⑤ ClientKeyExchange ──────────────────────→│
  │   - 用服务器公钥加密的 pre-master secret           │
  │   - ChangeCipherSpec(通知后续用协商的密钥)       │
  │   - Finished(验证整个握手过程)                   │
  │                                                    │
  │←──────── ⑥ ChangeCipherSpec ─────────────────────│
  │   - Finished(验证整个握手过程)                   │
  │                                                    │
  │ 双方根据 client random + server random + pre-master 计算 master secret
  │ 然后派生会话密钥(用于对称加密)                     │
  │                                                    │
  │──────── ⑦ 加密的 HTTP 数据 ─────────────────────→│
  │←──────── ⑦ 加密的 HTTP 数据 ─────────────────────│

该图描述的是 TLS 1.2 的 RSA 密钥交换,便于理解历史流程,但不代表所有 TLS 1.2 密码套件。采用 ECDHE 时,客户端和服务端交换临时密钥协商参数,证书私钥主要用于签名认证,并不会用来解密一个由客户端生成的 pre-master secret;ECDHE 还能提供前向保密。

图中 RSA 握手的关键点

  1. 客户端发起:随机数 + 密码套件
  2. 服务端回应:随机数 + 选定的密码套件 + 服务器证书
  3. 客户端验证证书,在该 RSA 示例中用证书公钥加密 pre-master secret 发送给服务端
  4. 双方独立计算 master secret(用 client random + server random + pre-master)
  5. 验证握手:Finished 消息包含前面所有内容的 hash,防止被篡改

2. TLS 1.3 握手(简化到 1-RTT)

Plain
TLS 1.3 重大改进:
- 1-RTT(往返一次)即可建立连接
- 0-RTT(重连时),甚至零往返
- 移除了不安全的算法(MD5、SHA-1、RC4、3DES 等)

握手流程:
1. 客户端 → ClientHello:随机数 + 密码套件 + key_share(DH 公钥)
2. 服务端 → ServerHello:随机数 + 选定的套件 + 服务端 key_share
            + Certificate + CertificateVerify + Finished
3. 客户端 → Finished(响应服务端)
握手完成,后续加密通信

3. TLS 1.3 关键特性

Plain
1. 前向保密(Forward Secrecy):
   即使服务器私钥泄漏,之前加密的会话仍然安全
   因为每次会话都用临时的 DH 公钥

2. 0-RTT:
   重连时客户端可以发送"早期数据"(带 ID)
   服务器解密后才能验证
   ⚠️ 风险:存在重放攻击可能,需谨慎使用

3. 加密更多握手信息:
   ServerHello 之后的大部分握手消息(包括证书)会被加密
   常规 TLS 1.3 的 ClientHello 仍是明文,因此其中的 SNI 默认可见;只有双方支持并成功使用 ECH 时才能隐藏相应 ClientHello 信息

4. 密码套件简化:
   TLS 1.2: 几十种
   TLS 1.3 将密钥交换与认证算法从对称密码套件名称中拆开,只保留认证加密算法和哈希组合,例如 TLS_AES_256_GCM_SHA384、TLS_AES_128_GCM_SHA256

四、CA 证书

1. 为什么需要 CA

Plain
问题:客户端怎么知道服务器的公钥是真的?

如果没有 CA:
- 客户端收到服务器的公钥
- 但是中间人可以伪造公钥
- 客户端无法验证真伪

CA 解决方案:
- 服务器的公钥由权威 CA 签名认证
- 客户端信任 CA(操作系统/浏览器内置根证书)
- 客户端用 CA 的公钥验证服务器的证书签名
- 如果验证通过,说明公钥确实是服务器的

2. 证书链

Plain
根 CA(自签名证书,受系统信任)

  ├── 中间 CA 1(由根 CA 签发)
  │     │
  │     └── 服务器证书(由中间 CA 1 签发)

  └── 中间 CA 2(由根 CA 签发)

        └── 服务器证书(由中间 CA 2 签发)

客户端验证服务器证书的流程:
1. 用中间 CA 的公钥验证服务器证书的签名
2. 用根 CA 的公钥验证中间 CA 证书的签名
3. 根 CA 的证书是受信任的(预装在系统中)
4. 整条链路验证通过 → 服务器可信

3. 证书内容

Plain
证书 X.509 标准包含:
- 颁发者(Issuer):CA 的标识
- 主体(Subject):拥有者的域名
- 有效期(Validity):起止时间
- 公钥(Public Key):服务器公钥
- 签名(Signature):CA 对证书的签名
- 序列号(Serial Number)
- 扩展(Extensions):如 SAN(多域名)

4. 自签名证书

Plain
开发环境常用 OpenSSL 生成:
openssl req -x509 -newkey rsa:2048 -nodes -keyout key.pem -out cert.pem -days 365

特点:
- 自己签发自己
- 不被浏览器/系统信任
- 用于本地开发、测试
- 面向公共互联网的站点通常使用受客户端信任的公共 CA 证书;受控的内网环境也可以部署自己的私有 CA,并把根证书安全地加入客户端信任库

5. HTTPS 证书生成与部署

Bash
# Let's Encrypt 免费证书(Certbot)
certbot certonly --standalone -d example.com

# Nginx 配置
server {
  listen 443 ssl http2;
  server_name example.com;

  ssl_certificate /path/to/fullchain.pem;
  ssl_certificate_key /path/to/privkey.pem;

  ssl_protocols TLSv1.2 TLSv1.3;
  ssl_ciphers HIGH:!aNULL:!MD5;
  ssl_prefer_server_ciphers on;

  # HSTS(强制 HTTPS)
  add_header Strict-Transport-Security "max-age=31536000" always;
}

# HTTP 重定向 HTTPS
server {
  listen 80;
  server_name example.com;
  return 301 https://$server_name$request_uri;
}

五、SSL 与 TLS 的关系

Plain
历史:
- SSL 1.0:Netscape 1995,未发布
- SSL 2.0:1995,2011 年被禁用(不安全)
- SSL 3.0:1996,2014 年 POODLE 攻击后被弃用
- TLS 1.0(1999):基于 SSL 3.0 改进
- TLS 1.1(2006):小改进
- TLS 1.2(2008):主流协议,支持现代算法
- TLS 1.3(2018):最新版本,1-RTT、强制前向保密

现在常说的 SSL 实际就是 TLS(甚至很多公司把 HTTPS 配置叫 SSL 配置)
推荐使用 TLS 1.3 + TLS 1.2,禁用 SSL 3.0、TLS 1.0、TLS 1.1

六、密码套件(Cipher Suite)

Plain
一个 TLS 密码套件字符串描述了握手和通信使用的算法:
例:TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

拆解:
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
└─┬─┘ └─┬──┘ └─┬┘ └────┬─────┘ └┬┘
  │     │      │        │        └─ MAC 算法(SHA256)
  │     │      │        └── 对称加密(AES 128 GCM)
  │     │      └── 身份认证(RSA 签名)
  │     └── 密钥交换(ECDHE,椭圆曲线 DH)
  └── 协议(TLS)

TLS 1.3 的密码套件简化为:
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_CCM_SHA256
TLS_AES_128_CCM_8_SHA256

TLS 1.3 默认所有套件都提供前向保密

七、HTTPS 性能优化

1. 性能成本

Plain
HTTPS 比 HTTP 多消耗的:
- TLS 握手:1-2 个 RTT(TLS 1.3 减少到 1-RTT)
- 加解密 CPU:现代 CPU 通常有 AES-NI 指令集,影响小
- 数据膨胀:加密 + MAC 增加少量字节

优化方向:
1. TLS 1.3(1-RTT 握手)
2. Session Ticket(会话复用,避免重新握手)
3. Session ID(会话复用)
4. False Start(TLS 1.2 优化,发送 Finished 前提前发数据)
5. OCSP Stapling(避免客户端实时查证书状态)
6. 硬件加速 / Nginx + OpenSSL AES-NI

2. 实际部署性能

Plain
HTTPS 优化清单:
✅ 启用 HTTP/2(多路复用,头压缩)
✅ 启用 TLS 1.3
✅ 配置会话复用(Session Ticket)
✅ 配置 HSTS(强制 HTTPS)
✅ 启用 OCSP Stapling
✅ 配置合适的密码套件
✅ 证书链完整且有效
✅ 启用 keep-alive

八、面试高频问答

Q1: 介绍一下 HTTPS 握手过程?

:HTTPS 基于 TLS 协议。以 TLS 1.2 为例:

  1. 客户端 → ClientHello:客户端发送支持的 TLS 版本、密码套件、客户端随机数
  2. 服务端 → ServerHello + Certificate + ServerHelloDone:服务端选定密码套件,发送自己的证书(含公钥),并发送服务端随机数
  3. 客户端验证证书:用本地根证书验证服务端证书链,确认公钥可信
  4. 客户端 → ClientKeyExchange + ChangeCipherSpec + Finished:客户端用服务端公钥加密 pre-master secret 发送过去,通知后续用对称密钥,并发送 Finished(包含前面所有内容的 hash)验证握手
  5. 服务端 → ChangeCipherSpec + Finished:服务端也通知后续用对称密钥,并发送自己的 Finished
  6. 双方计算 master secret:用 client random + server random + pre-master secret 计算 master secret,再派生出会话密钥
  7. 加密通信:后续用对称密钥加解密数据

TLS 1.3 把上述过程简化为 1-RTT,并强制使用前向保密。

Q2: 对称加密和非对称加密的区别?为什么 HTTPS 用两者?

维度对称加密非对称加密
密钥加解密同一密钥公钥 + 私钥
速度快(MB/s 量级)慢(KB/s 量级)
应用加密大量数据密钥交换、签名
问题密钥怎么传给对方?速度慢不适合大数据

HTTPS 用混合加密:非对称加密(RSA/ECDH)交换对称密钥,对称加密(AES/ChaCha20)加密数据。兼顾安全和性能。

Q3: 什么是 CA?证书怎么验证?

:CA(Certificate Authority)是权威的证书颁发机构。证书验证流程:

  1. 服务端提供证书(包含服务端公钥、域名、有效期、CA 签名)
  2. 客户端用 CA 的公钥验证证书签名
  3. 检查证书有效期、域名是否匹配
  4. 检查证书是否被吊销(OCSP / CRL)
  5. 验证通过 → 确认服务端公钥是真的

证书链验证时,要递归验证每一级 CA 证书,直到根 CA(操作系统/浏览器内置)。

Q4: 前向保密是什么?

:即使服务器的长期私钥泄漏,过去的加密会话仍然是安全的。原理:每次 TLS 握手用临时密钥对(DH/ECDH),协商出独立的会话密钥。长期私钥只用于身份认证,不参与会话密钥派生。即使长期私钥泄漏,也无法解密过去的会话。

TLS 1.3 强制使用支持前向保密的密码套件

Q5: 为什么不用纯非对称加密做 HTTPS?

:非对称加密(RSA)性能约为对称加密(AES)的 1/100 ~ 1/1000。对于大量数据(HTML/JS/CSS/图片),非对称加密会让 HTTPS 慢到不可用。混合加密方案(用非对称加密交换对称密钥 + 用对称加密数据)是最优解。

十、HTTP vs HTTPS 标准答法

30 秒标准版(必背)

HTTP 是明文传输,不安全;HTTPS = HTTP + SSL/TLS,在 HTTP 之下加了一层加密传输,核心是通过 TLS 握手协商出一个对称会话密钥,之后所有数据用这个密钥加密传输。

1 分钟进阶版(加分用)

  • HTTP 端口 80,HTTPS 端口 443
  • HTTPS 在 HTTP 与 TCP 之间多了一层 TLS/SSL 协议,提供加密、完整性校验、身份认证三大能力。
  • 加密方式:握手阶段通过证书签名完成身份认证,并通过 ECDHE 等机制协商共享秘密、派生密钥;应用数据阶段使用 AES-GCM、ChaCha20-Poly1305 等对称认证加密。RSA 可以用于签名,旧版 TLS 也曾支持 RSA 密钥传输;ECDHE 不是“非对称加密传输密钥”。
  • 身份认证:服务器提供 TLS 证书,由 CA 机构签名,浏览器验证证书合法性。
  • TLS 1.2 与 TLS 1.3 的完整握手往返次数取决于版本和握手路径;TLS 1.3 通常可在 1-RTT 后发送应用数据。0-RTT 只适用于恢复会话的早期数据,并有重放风险,不能称为完整首次握手。

十一、对称加密 vs 非对称加密

30 秒标准版(直接背)

对称加密:加密和解密用同一把密钥(如 AES)。速度快,适合大数据量加密,但密钥分发困难(如何安全地把密钥给对方)。

非对称加密:加密和解密用一对密钥(公钥 + 私钥)。公钥公开,私钥自己保留。速度慢,但解决密钥分发问题。

HTTPS 使用混合密码系统:握手阶段完成身份认证和密钥协商,双方派生对称流量密钥,再用对称认证加密保护应用数据。

1 分钟进阶版(加分用)

  • 对称加密:AES、DES、3DES、ChaCha20。加密 1GB 数据只比明文慢约 1-2 倍。
  • 公钥密码相关机制:RSA 可用于签名或特定加密方案,ECDSA/EdDSA 用于签名,DH/ECDH 用于密钥协商;“ECC”是椭圆曲线密码体系的统称。其成本和安全性质不能用一个固定倍数概括。
  • 混合密码系统:用 ECDHE 等机制建立共享秘密并派生临时对称密钥,再用 AES-GCM 等算法保护应用数据。
  • 数字签名:发送方用私钥生成签名,接收方用公钥按相应算法验证。把所有签名都描述为“私钥加密哈希、公钥解密”只适合非常粗略地类比部分 RSA 机制,不适用于 ECDSA 等算法。
  • 数字证书:CA 用私钥签名"服务器公钥 + 域名 + 有效期",浏览器用 CA 的公钥验证。

十二、关联文档